package jrain.fw.cfg.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import jrain.fw.core.cfg.CfgCallback;
import jrain.fw.core.cfg.CfgService;
import jrain.fw.core.dao.handler.IResultSetHandler;
import jrain.fw.core.log.Logger;
import jrain.fw.core.log.LoggerFactory;
import jrain.fw.core.service.DestroyService;
import jrain.fw.core.service.InitService;
import jrain.fw.core.service.Service;
import jrain.fw.core.service.ServiceConst;
import jrain.fw.core.utils.FwUtils;
import jrain.fw.dao.common.handler.RowMapHandler;
import jrain.fw.dao.common.handler.RowMapListHandler;
import jrain.utils.collection.RDMap;
import jrain.utils.collection.RMap;
import jrain.utils.exception.ServiceException;
import jrain.utils.lang.StringUtils;
import jrain.utils.prop.PropUtils;
import jrain.utils.sql.SqlUtils;

/**
 * <pre>
 * 作者：3244924214@qq.com 
 * 描述：配置存放在数据库中，该实现仅限开发调试环境使用。
 * </pre>
 */
@Service(name = "db", group = ServiceConst.S_CFG_SERVICE, module = ServiceConst.M_CFG, dependency = ServiceConst.S_JSON_SERVICE)
public class CfgDBService implements CfgService, InitService, DestroyService {

	private static final Logger log = LoggerFactory.getLogger("cfg-db");
	private DruidDataSource druidDataSource = null;
	private static Map<String, Object> cfgMap;

	@Override
	public RMap<String, Object> getCfgMap(String module) {
		RMap<String, Object> rsMap = getCfgMap(module, null);
		if (rsMap == null) {
			throw new ServiceException("Configuration module cannot be empty! module=" + module);
		}
		return rsMap;
	}

	@Override
	public RMap<String, Object> getCfgMap(String module, RMap<String, Object> defaultMap) {
		String envCode = StringUtils.trimNull(cfgMap.get("env.code"), "dev");
		Map<String, Object> rsMap = new HashMap<>();
		if ("sql".equals(module)) {
			String sql = "select busi_key,sql_code,sql_value,sql_table,sql_columns,sql_condition,sql_ext from jrain_cfg_business_sql where env_code = ?";
			List<Map<String, Object>> list = listBySql(sql, envCode);
			for (Map<String, Object> map : list) {
				String busiKey = StringUtils.trimNull(map.get("busiKey"));
				String sqlCode = StringUtils.trimNull(map.get("sqlCode"));
				String sqlValue = StringUtils.trimNull(map.get("sqlValue"));
				String sqlTable = StringUtils.trimNull(map.get("sqlTable"));
				String sqlColumns = StringUtils.trimNull(map.get("sqlColumns"));
				String sqlConditon = StringUtils.trimNull(map.get("sqlConditon"));
				String sqlExt = StringUtils.trimNull(map.get("sqlExt"));
				String sqlOrder = StringUtils.trimNull(map.get("sqlOrder"));
				Map<String, Object> sqlInfo = new HashMap<>();
				if (!StringUtils.isEmpty(sqlExt)) {
					Map<String, Object> sqlExtMap = FwUtils.getJsonService().toMap(sqlExt);
					sqlInfo.putAll(sqlExtMap);
				}
				if (!StringUtils.isEmpty(sqlOrder)) {
					Map<String, Object> sqlOrderMap = FwUtils.getJsonService().toMap(sqlOrder);
					sqlInfo.put("order", sqlOrderMap);;
				}
				sqlInfo.put("sql", sqlValue);
				sqlInfo.put("table", sqlTable);
				sqlInfo.put("columns", sqlColumns);
				sqlInfo.put("condition", sqlConditon);
				rsMap.put(busiKey + "." + sqlCode, sqlInfo);

			}
		} else if ("validate".equals(module)) {
			String sql = "select * from jrain_cfg_business_validate where env_code = ? order by row_sort asc";
			List<Map<String, Object>> lists = listBySql(sql, envCode);
			for (Map<String, Object> map : lists) {
				String busiKey = StringUtils.trimNull(map.get("busiKey"));
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> tempList = (List<Map<String, Object>>) rsMap.get(busiKey);
				if (tempList == null) {
					tempList = new ArrayList<>();
					rsMap.put(busiKey, tempList);
				}
				tempList.add(map);
			}
		} else {
			String sql = "select prop_code, item_key,item_value from jrain_cfg_prop where env_code=? and prop_code = ?";
			List<Map<String, Object>> list = listBySql(sql, envCode, module);
			if (list.size() == 0) {
				return defaultMap;
			}
			for (Map<String, Object> map : list) {
				String itemKey = StringUtils.trimNull(map.get("itemKey"));
				String itemValue = StringUtils.trimNull(map.get("itemValue"));
				if (!StringUtils.isEmpty(itemKey)) {
					rsMap.put(itemKey, itemValue);
				}
			}
		}
		return new RDMap<>(rsMap);
	}

	@Override
	public Object getCfgValue(String module, String key) {
		return getCfgValue(module, key, null);
	}

	@Override
	public Object getCfgValue(String module, String key, Object dvalue) {
		String envCode = StringUtils.trimNull(cfgMap.get("env.code"), "dev");
		if ("sql".equals(module)) {

			int lindex = key.lastIndexOf(".");
			String busiKey = key.substring(0, lindex);
			String sqlCode = key.substring(lindex + 1);
			String sql = "select sql_value,sql_table,sql_columns,sql_condition,sql_ext from jrain_cfg_business_sql where env_code =? and busi_key = ? and sql_code= ? ";
			Map<String, Object> map = queryBySql(sql, envCode, busiKey, sqlCode);
			if (map != null) {
				String sqlValue = StringUtils.trimNull(map.get("sqlValue"));
				String sqlTable = StringUtils.trimNull(map.get("sqlTable"));
				String sqlColumns = StringUtils.trimNull(map.get("sqlColumns"));
				String sqlConditon = StringUtils.trimNull(map.get("sqlConditon"));
				String sqlExt = StringUtils.trimNull(map.get("sqlExt"));
				String sqlOrder = StringUtils.trimNull(map.get("sqlOrder"));
				Map<String, Object> sqlInfo = new HashMap<>();
				if (!StringUtils.isEmpty(sqlExt)) {
					Map<String, Object> sqlExtMap = FwUtils.getJsonService().toMap(sqlExt);
					sqlInfo.putAll(sqlExtMap);
				}
				if (!StringUtils.isEmpty(sqlOrder)) {
					Map<String, Object> sqlOrderMap = FwUtils.getJsonService().toMap(sqlOrder);
					sqlInfo.put("order", sqlOrderMap);;
				}
				sqlInfo.put("sql", sqlValue);
				sqlInfo.put("table", sqlTable);
				sqlInfo.put("columns", sqlColumns);
				sqlInfo.put("condition", sqlConditon);
				return sqlInfo;
			}
			throw new ServiceException("configuration cannot be empty! module=" + module + ",key=" + key);
		} else if ("validate".equals(module)) {
			String sql = "select * from jrain_cfg_business_validate where env_code ? and busi_key = ? ";
			List<Map<String, Object>> lists = listBySql(sql, envCode, key);
			return lists;
		} else {
			String sql = "select prop_code,item_value from jrain_cfg_prop where env_code=? and prop_code = ? and item_key = ?";
			Map<String, Object> map = queryBySql(sql, envCode, module, key);
			if (map != null) {
				String itemValue = StringUtils.trimNull(map.get("itemValue"));
				return itemValue;
			}
		}
		return dvalue;
	}

	@Override
	public void setCfgValue(String module, RMap<String, Object> dataMap) {

	}

	@Override
	public void registerCfgCallBack(String module, CfgCallback callback) {

	}

	@Override
	public void unregisterCfgCallBack(String module) {

	}

	@Override
	public void unregisterCfgCallBack(String module, CfgCallback callback) {

	}

	@Override
	public void init() {
		try {
			cfgMap = PropUtils.getClasspathConf("cfg.conf");
			this.druidDataSource = new DruidDataSource();
			List<Filter> filters = new ArrayList<>();
			Slf4jLogFilter filter = new Slf4jLogFilter();
			filter.setStatementExecutableSqlLogEnable(true);
			filters.add(filter);
			druidDataSource.setProxyFilters(filters);
			DruidDataSourceFactory.config(druidDataSource, cfgMap);
			log.info("{} classpath started!", ServiceConst.S_CFG_SERVICE);
		} catch (Throwable t) {
			log.info(ServiceConst.S_CFG_SERVICE + " classpath started!", t);
		}
	}

	@Override
	public void destroy() {
		if (druidDataSource != null) {
			druidDataSource.close();
		}
		log.info("{} db stoped!", ServiceConst.S_CFG_SERVICE);
	}

	private Map<String, Object> queryBySql(String sql, Object... params) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = druidDataSource.getConnection();
			pstmt = conn.prepareStatement(sql);
			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i + 1, params[i]);
				}
			}
			rs = pstmt.executeQuery();
			IResultSetHandler<Map<String, Object>> handler = new RowMapHandler();
			Map<String, Object> rsMap = handler.handle(rs, new HashMap<>());
			return rsMap;
		} catch (Exception e) {
			throw new ServiceException(e.getMessage(), e);
		} finally {
			SqlUtils.closeRs(rs);
			rs = null;
			SqlUtils.closeStmt(pstmt);
			pstmt = null;
			SqlUtils.closeConn(conn);
			conn = null;
		}
	}

	private List<Map<String, Object>> listBySql(String sql, Object... params) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = druidDataSource.getConnection();
			pstmt = conn.prepareStatement(sql);
			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i + 1, params[i]);
				}
			}
			rs = pstmt.executeQuery();
			IResultSetHandler<List<Map<String, Object>>> handler = new RowMapListHandler();
			List<Map<String, Object>> list = handler.handle(rs, new HashMap<>());
			return list;
		} catch (Exception e) {
			throw new ServiceException(e.getMessage(), e);
		} finally {
			SqlUtils.closeRs(rs);
			rs = null;
			SqlUtils.closeStmt(pstmt);
			pstmt = null;
			SqlUtils.closeConn(conn);
			conn = null;
		}
	}

	public static void main(String[] args) {
		String str = "test.default";
		int s = str.lastIndexOf(".");
		System.out.println(str.substring(0, s));
	}
}
